﻿// -----------------------------------------------------------------------
// <copyright file="Columnar.cs" company="Hewlett-Packard">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace SecutityLib
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// columnar technnique
    /// </summary>
    public class Columnar : EncodingDecodingTech
    {
        /// <summary>
        /// Encodes the specified plain text.
        /// </summary>
        /// <param name="plainText">The plain text.</param>
        /// <param name="key">The key.</param>
        /// <returns>
        /// cipher text
        /// </returns>
        public override string Encode(string plainText, string key)
        {
            this.CheckText(plainText);

            int[] keyArr = this.GetKey(key);
            int keylength = keyArr.Length;
            char[] plain;

            plain = plainText.ToCharArray();
            int numberOfRows = plain.Length / keylength;

            if (plain.Length % keylength != 0)
            {
                numberOfRows++;
            }

            char[,] plainArr = new char[numberOfRows, keylength];
            char[] cipher = new char[numberOfRows * keylength];

            int cnt = 0;
            for (int i = 0; i < plainArr.GetLength(0); i++)
            {
                for (int j = 0; j < keylength; j++)
                {
                    if (cnt >= plain.Length)
                    {
                        plainArr[i, j] = 'x';
                    }
                    else
                    {
                        plainArr[i, j] = plain[cnt++];
                    }
                }
            }

            int cipherCnt = 0;
            for (int x = 0; x < keylength; x++)
            {
                int count = x + 1;
                int index = 0;
                for (int y = 0; y < keylength; y++)
                {
                    if (keyArr[y] == count)
                    {
                        index = y;
                        break;
                    }
                }

                for (int i = 0; i < numberOfRows; i++)
                {
                    cipher[cipherCnt++] = plainArr[i, index];
                }
            }

            return new string(cipher);
        }

        /// <summary>
        /// Decodes the specified plain text.
        /// </summary>
        /// <param name="cipherText">The cipher text.</param>
        /// <param name="key">The key.</param>
        /// <returns>
        /// cipher text
        /// </returns>
        public override string Decode(string cipherText, string key)
        {
            this.CheckText(cipherText);

            int[] keyArr = this.GetKey(key);
            int keylength = keyArr.Length;

            char[] cipher = cipherText.ToCharArray();

            char[] plain = new char[cipherText.Length];

            int numberOfRows = cipherText.Length / keylength;

            char[,] plainArr = new char[numberOfRows, keylength];

            int cipherCnt = 0;

            for (int x = 0; x < keylength; x++)
            {
                int count = x + 1;
                int index = 0;
                for (int y = 0; y < keylength; y++)
                {
                    if (keyArr[y] == count)
                    {
                        index = y;
                        break;
                    }
                }

                for (int i = 0; i < numberOfRows; i++)
                {
                    plainArr[i, index] = cipher[cipherCnt++];
                }
            }

            int cnt = 0;
            for (int i = 0; i < numberOfRows; i++)
            {
                for (int j = 0; j < keylength; j++)
                {
                    plain[cnt++] = plainArr[i, j];
                }
            }

            return new string(plain);
        }

        /// <summary>
        /// Gets the key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>key array</returns>
        public int[] GetKey(string key)
        {
            string[] temp = key.Split(',');
            int[] keys = new int[temp.Length];
            for (int i = 0; i < keys.Length; i++)
            {
                try
                {
                    keys[i] = int.Parse(temp[i]);
                }
                catch
                {
                    throw new Exception("Key must be integers");
                }
            }

            int cnt = 0;

            for (int i = 0; i < temp.Length; i++)
            {
                for (int j = 0; j < temp.Length; j++)
                {
                    if (keys[j] == cnt + 1)
                    {
                        cnt++;
                        break;
                    }
                }
            }

            if (cnt != temp.Length)
            {
                throw new System.Exception("Invalid Key sequence");
            }

            return keys;
        }

        /// <summary>
        /// Checks the text.
        /// </summary>
        /// <param name="text">The text.</param>
        private void CheckText(string text)
        {
            for (int i = 0; i < text.Length; i++)
            {
                if (text[i] < 'a' || text[i] > 'z')
                {
                    throw new Exception("Text must be char");
                }
            }
        }
    }
}